﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using GraphTest.Geometry2D;

namespace GraphTest
{
    public class MyRect : Rectangle2D
    {
        public MyRect(float left, float top, float width, float height)
            : base(new Point2D(left, top), new Vector2D(width, height))
        {
            Left = left;
            Top = top;
            Width = width;
            Height = height;

            Brush = Brushes.Green;
            PenWidth = 1;

            DrugAndDrop = false;

            Epsilon = 2;
            SelectedSide = Rectangle2DSide.None;
            SelectedSideCursorSize = 10;
            SelectedSideCursorBrush = Brushes.Red;
        }

        public Rectangle Rect
        {
            get { return GetRectangle(); }
        }

        public float Left { get; set; }
        public float Top { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }

        public Brush Brush { get; set; }
        public float PenWidth { get; set; }

        public bool DrugAndDrop { get; set; }

        public float Epsilon { get; set; }
        public Rectangle2DSide SelectedSide { get; set; }
        public int SelectedSideCursorSize { get; set; }
        public Brush SelectedSideCursorBrush { get; set; }

        public int LocalMouseX { get; set; }
        public int LocalMouseY { get; set; }

        public bool Resize { get; set; }
        public int MouseDownX { get; set; }
        public int MouseDownY { get; set; }



        public bool IsMouseIn(int X, int Y)
        {
            return Left <= X && X <= Left + Width && Top <= Y && Y <= Top + Height;
        }

        protected Point2D PrevMousePosition = null;

        public bool OnMouseMove(Point p, Size borders, List<MyRect> rects)
        {
            if (!DrugAndDrop)
                PrevMousePosition = null;            
            
            bool shouldbeInvalidated = false;

            if (Resize)
            {
                if (SelectedSide == Rectangle2DSide.Top)
                {
                    int delta = (int)((float)p.Y - Top);
                    Top = p.Y;
                    Height -= delta;
                }

                if (SelectedSide == Rectangle2DSide.Bottom)
                {
                    Height = p.Y - Top;
                }

                if (SelectedSide == Rectangle2DSide.Left)
                {
                    int delta = (int)((float)p.X - Left);
                    Left = p.X;
                    Width -= delta;
                }

                if (SelectedSide == Rectangle2DSide.Right)
                {
                    Width = p.X - Left;
                }

                shouldbeInvalidated |= true;
            }
            else
            {
                var oldRSelectedSide = SelectedSide;
                SelectedSide = FindIntersectedSide(p.X, p.Y);
                shouldbeInvalidated |= SelectedSide != oldRSelectedSide;

                if (DrugAndDrop)
                {
                    if (PrevMousePosition == null)
                        PrevMousePosition = new Point2D(p.X, p.Y);

                    //Vector2D shift = new Vector2D(-LocalMouseX, -LocalMouseY);

                    Vector2D shift = new Vector2D(p.X - PrevMousePosition.X, p.Y - PrevMousePosition.Y);

                    PrevMousePosition = new Point2D(p.X, p.Y);

                    if (rects != null && rects.Count > 0)
                    {
                        rects.ForEach(r =>
                            {
                                Vector2D currShift = Geometry2DHelper.FindMaxUncollisionShift(r, this, shift);
                                if (currShift.Module() < shift.Module())
                                    shift = currShift;
                            });
                    }

                    //int newLeft = (int)(p.X - LocalMouseX);
                    //int newRight = (int)(p.X - LocalMouseX + Width);
                    //int newTop = (int)(p.Y - LocalMouseY);
                    //int newBottom = (int)(p.Y - LocalMouseY + Height);

                    //int newLeft = (int)(p.X + shift.X);
                    //int newRight = (int)(p.X + shift.X + Width);
                    //int newTop = (int)(p.Y + shift.Y);
                    //int newBottom = (int)(p.Y + shift.Y + Height);

                    int newLeft = (int)(Left + shift.X);
                    int newRight = (int)(Left + Width);
                    int newTop = (int)(Top + shift.Y);
                    int newBottom = (int)(Top + Height);

                    if (!(newLeft >= 0 && newRight <= borders.Width
                        && newTop >= 0 && newBottom <= borders.Height))
                    {
                        if (newLeft < 0)
                            Left = 0;

                        if (newRight > borders.Width)
                            Left = borders.Width - Width;

                        if (newTop < 0)
                            Top = 0;

                        if (newBottom > borders.Height)
                            Top = borders.Height - Height;
                    }
                    else
                    {

                        Left = newLeft;
                        Top = newTop;
                    }

                    shouldbeInvalidated |= true;
                }
            }

            return shouldbeInvalidated;
        }

        public void OnMouseUp(Point p)
        {
            Resize = false;
            DrugAndDrop = false;
        }

        public void OnMouseDown(Point p)
        {
            Resize = IsMouseInSelectedSideCursor(p.X, p.Y);
            if (Resize)
            {
                DrugAndDrop = false;

                MouseDownX = p.X;
                MouseDownY = p.Y;
            }
            else
            {
                DrugAndDrop = IsMouseIn(p.X, p.Y);
                if (DrugAndDrop)
                {
                    LocalMouseX = (int)((float)p.X - Left);
                    LocalMouseY = (int)((float)p.Y - Top);
                }
            }
        }


        public bool IsMouseInSelectedSideCursor(int X, int Y)
        {
            if (SelectedSide == Rectangle2DSide.None)
                return false;

            int centerX = 0;
            int centerY = 0;
            if (SelectedSide == Rectangle2DSide.Top)
            {
                centerX = (int)(Left + Width / 2);
                centerY = (int)Top;
            }
            else if (SelectedSide == Rectangle2DSide.Right)
            {
                centerX = (int)(Left + Width);
                centerY = (int)(Top + Height / 2);
            }
            else if (SelectedSide == Rectangle2DSide.Bottom)
            {
                centerX = (int)(Left + Width / 2);
                centerY = (int)(Top + Height);
            }
            else
            {
                centerX = (int)Left;
                centerY = (int)(Top + Height / 2);
            }

            Pen pc = new Pen(SelectedSideCursorBrush, 1);
            Rectangle cursorRect = new Rectangle(centerX - SelectedSideCursorSize / 2, centerY - SelectedSideCursorSize / 2, SelectedSideCursorSize, SelectedSideCursorSize);

            return cursorRect.Contains(X, Y);
        }

        public Rectangle2DSide FindIntersectedSide(int X, int Y)
        {
            Rectangle2D top = new Rectangle2D(Left, Top - Epsilon, Width, Epsilon + Epsilon);
            if (top.Contains(X, Y))
                return Rectangle2DSide.Top;

            Rectangle2D right = new Rectangle2D(Left + Width - Epsilon, Top, Epsilon + Epsilon, Height);
            if (right.Contains(X, Y))
                return Rectangle2DSide.Right;

            Rectangle2D bottom = new Rectangle2D(Left, Top + Height - Epsilon, Width, Epsilon + Epsilon);
            if (bottom.Contains(X, Y))
                return Rectangle2DSide.Bottom;

            Rectangle2D left = new Rectangle2D(Left - Epsilon, Top, Epsilon + Epsilon, Height);
            if (left.Contains(X, Y))
                return Rectangle2DSide.Left;

            return Rectangle2DSide.None;
        }

        public void Paint(Graphics G)
        {
            //new System.Drawing.L

            Pen p = new Pen(Brush, PenWidth);

            G.DrawRectangle(p, Left, Top, Width, Height);
            //G.DrawLine(p, 0, 0, Left, Top);
            //G.DrawLine(p, G.VisibleClipBounds.Width, 0, Left + Width, Top);
            //G.DrawLine(p, G.VisibleClipBounds.Width, G.VisibleClipBounds.Height, Left + Width, Top + Height);
            //G.DrawLine(p, 0, G.VisibleClipBounds.Height, Left, Top + Height);

            if (SelectedSide != Rectangle2DSide.None)
            {
                int centerX = 0;
                int centerY = 0;
                if (SelectedSide == Rectangle2DSide.Top)
                {
                    centerX = (int)(Left + Width / 2);
                    centerY = (int)(Top);
                }
                else if (SelectedSide == Rectangle2DSide.Right)
                {
                    centerX = (int)(Left + Width);
                    centerY = (int)(Top + Height / 2);
                }
                else if (SelectedSide == Rectangle2DSide.Bottom)
                {
                    centerX = (int)(Left + Width / 2);
                    centerY = (int)(Top + Height);
                }
                else
                {
                    centerX = (int)(Left);
                    centerY = (int)(Top + Height / 2);
                }

                Pen pc = new Pen(SelectedSideCursorBrush, 1);
                G.DrawRectangle(pc, centerX - SelectedSideCursorSize / 2, centerY - SelectedSideCursorSize / 2, SelectedSideCursorSize, SelectedSideCursorSize);
            }
        }

        //public RSide FindContainedSide(Rectangle r)
        //{
        //    if ((!r.Contains(Rect)) && (!Rect.Contains(r)))
        //        return RSide.None;

        //    Rect.Contains(r.Left, r.Top) && 
        //}
    }
}
